#pragma once
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <time.h>
#include <filesystem>
#include <fstream>
#include <sstream>
#include "Mutex.hpp"
namespace LogModule
{
    using namespace MutexModule;

    // 1.默认路径和文件名
    std::string default_path = "./log/";
    std::string default_filename = "log.txt";
    // 2.日志等级
    enum class LogLevel
    {
        DEBUG = 1,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    std::string CurrTime()
    {
        time_t t = time(nullptr);
        struct tm cur_time;
        localtime_r(&t, &cur_time);
        char buff[64];
        snprintf(buff, sizeof(buff), "%4d-%02d-%02d %02d:%02d:%02d", cur_time.tm_year + 1900, cur_time.tm_mon + 1, cur_time.tm_mday, cur_time.tm_hour, cur_time.tm_min, cur_time.tm_sec);
        return buff;
    }
    std::string LevelToString(LogLevel level)
    {
        switch (level)
        {
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::WARNING:
            return "WARNING";
        case LogLevel::FATAL:
            return "FATAL";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::ERROR:
            return "ERROR";
        default:
            return "None";
        }
    }
    // 3.刷新策略
    class LogStrategy
    {
    public:
        virtual ~LogStrategy() {}
        virtual void SyncMessage(std::string message) {}
    };
    // 3.1显示器刷新
    class ConsoleStrategy : public LogStrategy
    {
    public:
        ConsoleStrategy()
        {
        }
        ~ConsoleStrategy()
        {
        }
        void SyncMessage(std::string message) override
        {
            // 向显示器上打印
            LockGuard lockguard(_mutex);
            std::cout << message << std::endl;
        }

    private:
        Mutex _mutex;
    };
    // 3.2文件刷新
    class FileStrategy : public LogStrategy
    {
    public:
        FileStrategy(std::string path = default_path, std::string filename = default_filename)
            : _path(path),
              _filename(filename)
        {
            std::string fullpath = _path + _filename;
            // 判断文件是否存在
            LockGuard lockgurad(_mutex);
            if (std::filesystem::exists(fullpath))
            {
                return;
            }
            try
            {
                // 不存在就创建
                std::filesystem::create_directories(_path);
            }
            catch (std::filesystem::filesystem_error &e)
            {

                std::cerr << e.what() << std::endl;
            }
        }
        ~FileStrategy()
        {
        }
        void SyncMessage(std::string message) override
        {
            std::string fullpath =  _path+_filename;
            // 日志写入一定是追加
            std::ofstream of(fullpath, std::ios_base::app);
            LockGuard lockguard(_mutex);
            of << message << std::endl;
        }

    private:
        std::string _filename;
        std::string _path;
        Mutex _mutex;
    };

    // 4.日志类
    class Logger
    {
    public:
        Logger()
            : _strategy(new ConsoleStrategy())
        {
        }
        ~Logger()
        {
        }

        class LogMessage
        {
        public:
            LogMessage(LogLevel level, int line, std::string filename, Logger &logger)
                : _logger(logger),
                  _curr_time(CurrTime()),
                  _level(level),
                  _pid(getpid()),
                  _filename(filename),
                  _line(line)
            {
                //[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] - hello world
                _info = "[" + _curr_time + "] " +
                        "[" + LevelToString(_level) + "] " +
                        "[" + std::to_string(_pid) + "] " +
                        "[" + _filename + "] " +
                        "[" + std::to_string(_line) + "] - ";
            }
            template <class T>
            LogMessage &operator<<(T data)
            {
                std::stringstream ss;
                ss << data;
                _info += ss.str();
                return *this;
            }
            ~LogMessage()
            {
                _logger._strategy->SyncMessage(_info);
            }

        private:
            Logger &_logger;
            std::string _curr_time; // 当前时间
            LogLevel _level;        // 日志等级
            pid_t _pid;             // pid
            std::string _filename;  // 文件名
            int _line;              // 行号
            std::string _info;      // 日志信息
        };
        // LogMessage operator()(LogLevel level, int line, std::string filename, Logger &logger)
        LogMessage operator()(LogLevel level, int line, std::string filename)
        {
            LogMessage logmessage(level, line, filename, *this);
            return logmessage;
        }
        void EnableConsole()
        {
            _strategy = std::make_shared<ConsoleStrategy>();
        }
        void EnableFile()
        {
            _strategy = std::make_shared<FileStrategy>();
        }

    private:
        std::shared_ptr<LogStrategy> _strategy; // 刷新策略
    };
    Logger logger;

#define LOG(level) logger(level, __LINE__, __FILE__)
#define ENABLE_CONSOLE() logger.EnableConsole()
#define ENABLE_FILE() logger.EnableFile();
}